package util.tools;

import constant.Constant;
import cucumber.api.Scenario;
import cucumber.runtime.ClassFinder;
import cucumber.runtime.Runtime;
import cucumber.runtime.RuntimeOptions;
import cucumber.runtime.io.MultiLoader;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.io.ResourceLoaderClassFinder;
import io.appium.java_client.MobileBy;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import test_achieve.DataStatistics;
import util.JdbcUtil;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cucumber.api.cli.Main.run;
import static java.util.Arrays.asList;

/**
 * Created by chenkuo on 2018/1/4.
 */
public class CommonTools {

    /**
     * 元素定位
     * by为：id,className,xpath,name等
     */
    public static WebElement findElement(WebDriver driver, String by, String param) {
        try {
            Method method = By.class.getDeclaredMethod(by, String.class);
            By b = (By) method.invoke(null, param);
            return driver.findElement(b);
        } catch (Exception e) {
            System.out.println("要找的元素不存在,通过" + by + "定位；元素信息：" + param);
            takeScreenShot(driver, param);
            throw new RuntimeException("页面元素获取异常");
        }
    }


    /**
     * 查看元素是否存在
     * by为：id,className,xpath,name等
     */
    public static boolean checkElementExit(WebDriver driver, String by, String param) {
        boolean flag = false;
        try {
            driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
            Method method = By.class.getDeclaredMethod(by, String.class);
            By b = (By) method.invoke(null, param);
            driver.findElement(b);
            flag = true;
        } catch (Exception e) {
            flag = false;
        } finally {
            driver.manage().timeouts().implicitlyWait(Constant.hideWaitTime, TimeUnit.SECONDS);
        }
        return flag;
    }

    /**
     * 查看元素是否存在
     * 现在建议用这种方式去写元素检查
     */
    public static boolean checkElementExit(WebDriver driver, By by) {
        boolean flag = false;
        try {
            driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
            driver.findElement(by);
            flag = true;
        } catch (Exception e) {
            flag = false;
        } finally {
            driver.manage().timeouts().implicitlyWait(Constant.hideWaitTime, TimeUnit.SECONDS);
        }
        return flag;
    }

    /**
     * 等待元素加载出现
     * by为：id,className,xpath,name等
     */

    public static boolean waitElementLoad(WebDriver driver, String by, String param) throws Exception {
        try {
            WebDriverWait wait = new WebDriverWait(driver, 20);
            Method method = By.class.getDeclaredMethod(by, String.class);
            By b = (By) method.invoke(null, param);
            wait.until(ExpectedConditions.presenceOfElementLocated(b));
        } catch (Exception e) {
            CommonTools.takeScreenShot(driver, param);
            throw new Exception("元素没有出现，元素名：" + param);
        }

        return true;
    }

    /**
     * 等待元素加载出现
     * 现在建议用这种方法写元素等待
     */

    public static boolean waitElementLoad(WebDriver driver, By by) throws Exception {
        boolean flag = false;
        try {
            WebDriverWait wait = new WebDriverWait(driver, 20);
            wait.until(ExpectedConditions.presenceOfElementLocated(by));
        } catch (Exception e) {
            flag = false;
            System.out.println("元素没有出现");
        }

        return flag;
    }


//    /**点击重新封装*/
//    public static void click(WebDriver driver, String by, String param) throws Exception {
//        try {
//            CommonTools.waitElementLoad(driver,by,param);
//        }catch (Exception e){
//            System.out.println("要找的元素不存在,通过"+by+"定位；元素信息："+param);
//            takeScreenShot(driver,param);
//        }
//        CommonTools.findElement(driver,by,param).click();
//    }

    /**
     * 获取元素信息
     */
    public static String getText(WebDriver driver, String by, String param) throws Exception {
        try {
            CommonTools.waitElementLoad(driver, by, param);
        } catch (Exception e) {
            System.out.println("要找的元素不存在,通过" + by + "定位；元素信息：" + param);
            takeScreenShot(driver, param);
            throw new RuntimeException("页面元素获取异常");
        }
        return CommonTools.findElement(driver, by, param).getText();
    }

    /**
     * 屏幕截图
     * 只有火狐浏览器可以，chrome会报错
     */
    public static void takeScreenShot(WebDriver driver, String name) {
        File screenShotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        try {
            FileUtils.copyFile(screenShotFile, new File("C:\\jietu\\" + getCurrentDateTime() + name + ".jpg"));
            System.out.println("截图位置：" + "C:\\jietu\\" + getCurrentDateTime() + name + ".jpg");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String getCurrentDateTime() {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd_HHmmss");//设置日期格式
        return df.format(new Date());
    }

    /**
     * 屏幕截图
     * 只有火狐浏览器可以，chrome会报错
     */
    public static void takeChromeScreenShot(WebDriver driver, String name) {
        System.out.println("谷歌浏览器截图");
    }


    /**
     * 获取当前的系统时间
     * day为0：今天
     * day为-1：昨天
     * day为1：明天
     */
    public static String getDateUnixTime(int day) {
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.add(Calendar.DAY_OF_MONTH, day);
        String time = String.valueOf(cal.getTime().getTime());
        return time;
    }


    /**
     * 延迟判断,元素的Text与预期相同
     */

    public static boolean waitForResultByClassName(WebDriver driver, String result, String by) throws InterruptedException {
        boolean btn = false;
        for (int i = 0; i < 10; i++) {
            String result1 = driver.findElement(By.className(by)).getText();
            if (result.equals(result1)) {
                btn = true;
                break;
            }
            Thread.sleep(1000);
        }
        return btn;
    }

    public static boolean waitForResultById(WebDriver driver, String result, String by) throws InterruptedException {
        boolean btn = false;
        for (int i = 0; i < 10; i++) {
            String result1 = driver.findElement(By.id(by)).getText();
            System.out.println("页面金额：" + result1);
            System.out.println("想要金额：" + result);
            if (result.equals(result1)) {
                btn = true;
                break;
            }
            Thread.sleep(1000);
        }
        return btn;
    }

    public static boolean waitForResultByXpath(WebDriver driver, String result, String by) throws InterruptedException {
        boolean btn = false;
        for (int i = 0; i < 10; i++) {
            String result1 = driver.findElement(By.xpath(by)).getText();
            if (result.equals(result1)) {
                btn = true;
                break;
            }
            Thread.sleep(1000);
        }
        return btn;
    }


    /**
     * 滚动到制定的元素出现
     *
     * @param driver
     * @param by
     */
    public static void scrollToElement(WebDriver driver, By by) {
        WebElement e = driver.findElement(by);
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].scrollIntoView(true);", e);
    }

    /**
     * 滚动到制定的元素出现
     *
     * @param driver
     * @param
     */
    public static void scrollToElement(WebDriver driver, WebElement e) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].scrollIntoView(true);", e);
    }

    /**
     * 根据输入的日期返回 正确的日期格式
     *
     * @param mydate 今天或明天
     * @return 这种日期格式 2017-9-7
     */
    public static String getDate(String mydate) {
        Date date = new Date();//取时间
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        if (mydate.contains("明")) {//如果日期 是 明天，或是 明日
            calendar.add(calendar.DATE, 1);//把日期往后增加一天.整数往后推,负数往前移动
        }
        date = calendar.getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-M-d");
        String dateString = formatter.format(date);
        return dateString;
    }

    /**
     * 根据输入的日期返回 正确的日期格式
     *
     * @param mydate 今天或明天
     * @return 这种日期格式 2017-09-07
     */
    public static String getDate2(String mydate) {
        Date date = new Date();//取时间
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        if (mydate.contains("明")) {//如果日期 是 明天，或是 明日
            calendar.add(calendar.DATE, 1);//把日期往后增加一天.整数往后推,负数往前移动
        }
        date = calendar.getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = formatter.format(date);
        return dateString;
    }

    /**
     * 根据输入的日期返回 正确的日期格式
     *
     * @param count 第几天
     * @return 这种日期格式 2017-09-07
     */
    public static String getDateCount(int count) {
        Date date = new Date();//取时间
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.DATE, count);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = formatter.format(date);
        return dateString;
    }

    /**
     * 返回今天的日期格式精确到小时
     *
     * @return 这种日期格式 2017-09-07-02
     */
    public static String getDateHour() {
        Date date = new Date();//取时间
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.DATE, 0);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH");
        String dateString = formatter.format(date);
        return dateString;
    }


    /**
     * 根据i值，进行i次返回
     *
     * @param driver
     * @param count  例如 count=2 返回两级
     */
    public static void back(WebDriver driver, int count) {
        for (int i = 0; i < count; i++) {
            driver.navigate().back();
        }
    }

    /**
     * 把一个字符串中特殊的字符替换掉
     *
     * @param s   被替换的字符串
     * @param reg 被替换掉的字符
     * @param exp 用于替换的字符
     * @return 例如：(aaa-bbb,-,c )那么执行结果为 aaacbbb
     */
    public static String stringChange(String s, String reg, String exp) {
        String ss = s.replaceAll(reg, exp);

        return ss;
    }

    /**
     * 显式等待 判断元素是否存在
     *
     * @param driver
     * @param by     通过By查找元素
     * @return
     */
    public static Boolean exist(AndroidDriver driver, final By by) {
        WebDriverWait wait = new WebDriverWait(driver, 2);
        Boolean flag = wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver input) {
                return input.findElement(by).getText().contains("您的订单已取消");
            }
        });
        return flag;
    }

    /**
     * 在闪送员今日订单页中，根据订单号，确定元素的排序
     *
     * @param orderN
     * @return 例如返回 0 为第一个元素，返回1为第二个元素
     */
    public static int getIndexByorderNumber(AndroidDriver driver, String orderN) {
        int i = driver.findElements(By.id("tasknum_txt")).size();
        for (int k = 0; k < i; k++) {
            AndroidElement ae = (AndroidElement) driver.findElements(By.id("tasknum_txt")).get(k);
            if (orderN.equals(ae.getText())) {
                return k;
            }
        }
        return -1;
    }

    /**
     * 字符串中的数字截取
     * "sep"为截取数字里面的部分（如果有特殊字符可能涉及到转译）
     * "num"为第几个
     */
    public static String splitNumber(String Char, String sep, int num) {
        String regExp = sep + "([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])";
        Pattern p = Pattern.compile(regExp);
        Matcher m = p.matcher(Char);
        int i = 0;
        int countPosition = num;
        String result = null;
        while (m.find()) {
            ++i;
            result = m.group();
            result = result.substring(sep.length(), result.length());
            if (i == countPosition) {
                break;
            }
        }
        return result;
    }

    /**
     * 截取字符串包含部分
     * Char 字符串
     * Start 截取起始部分
     * End  截取结束部分
     */
    public static String cutContain(String Char, String Start, String End) {
//        String [] abc = Char.split("{""");
        return "";
    }

    /**
     * 截取字符串前面部分
     * Char 要截取的字符串
     * End  截止部分
     */
    public static String cutFront(String Char, String End) {
        String result = Char.substring(0, Char.indexOf(End));
        return result;
    }

    /**
     * 截取字符串中间部分
     * Char 要截取的字符串
     * Start  截止部分
     */
    public static String cutMiddle(String Char, String Start, String End) {
        String result = Char.substring(Char.indexOf(Start) + Start.length(), Char.indexOf(End));
        return result;
    }

    /**
     * 截取字符串末尾部分
     * Char 要截取的字符串
     * End  截止部分
     */
    public static String cutEnd(String Char, String Start) {
        if (!(Char.contains(Start))) {
            System.out.println("不包含指定内容");
            return "";
        }
        String result = Char.substring(Char.indexOf(Start) + Start.length(), Char.length());
        return result;
    }


    /**
     * 判断字符串是否存在指定字符串
     * Char 要截取的字符串
     * Start  截止部分
     */
    public static void assertStringContain(String Char, String CharTwo) {
        boolean btn = Char.contains(CharTwo);
        if (btn == false) {
            System.out.println("页面内容：" + Char + "不包含：" + CharTwo);
        }
        Assert.assertEquals(btn, true);
    }


    //截取数字
    public static String getNumbers(String content) {
        Pattern pattern = Pattern.compile("\\d+(\\.\\d*)?");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            return matcher.group(0);
        }
        return "";
    }

    /**
     * 根据UIAutomator的识别方式，判断元素是否存在
     *
     * @param s
     * @return
     */
    public static Boolean isElementExist(AndroidDriver driver, String s) {
        //Constant.clientDriver.findElementByAndroidUIAutomator("new UiSelector().text(\""+city+"\")")
        //driver.findElementByAndroidUIAutomator("new UiSelector().text(\""+s+"\")").click();
        try {
            driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
            driver.findElementByAndroidUIAutomator(s);
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            return false;
        }
    }


    /**
     * 根据MobileBy的识别方式，判断元素是否存在
     *
     * @param s
     * @return
     */
    public static Boolean isElementExist2(AndroidDriver driver, String s) {
//        Constant.clientDriver.findElement(MobileBy.AccessibilityId("btn")).click();
        try {
            driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
            driver.findElement(MobileBy.AccessibilityId(s));
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            return false;
        }
    }

    /**
     * 根据UIAutomator的识别方式，判断元素是否存在
     *
     * @param s
     * @return
     */
    public static Boolean isElementExistByName(AndroidDriver driver, String s) {
        //Constant.clientDriver.findElementByAndroidUIAutomator("new UiSelector().text(\""+city+"\")")
        //driver.findElementByAndroidUIAutomator("new UiSelector().text(\"下一步\")").click();
        try {
            driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
            driver.findElementByAndroidUIAutomator("new UiSelector().text(\"" + s + "\")");
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            return false;
        }
    }

    /**
     * 根据by 判断元素是否存在
     *
     * @param by
     * @return
     */

    public static Boolean isElementExist(WebDriver driver, By by) {
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
        try {
            driver.findElement(by);
            driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
            return false;
        }
    }

    /**
     * 向左滑动(从屏幕最左侧)
     */
    public static void swipLeft(AndroidDriver driver) {
        int width = driver.manage().window().getSize().width;//手机屏宽
        int height = driver.manage().window().getSize().height;//手机屏高
        driver.swipe(width * 24 / 25, height / 2, width / 4, height / 2, 200);//向左滑动
    }

    /**
     * 向右滑动(从屏幕最右侧)
     */
    public static void swipRight(AndroidDriver driver) {
        int width = driver.manage().window().getSize().width;//手机屏宽
        int height = driver.manage().window().getSize().height;//手机屏高
        driver.swipe(width * 1 / 25, height / 2, width * 24 / 25, height / 2, 200);//向右滑动
    }

    /**
     * 向上滑动
     */
    public static void swipeUp(AndroidDriver driver) {
        int width = driver.manage().window().getSize().width;//手机屏宽
        int height = driver.manage().window().getSize().height;//手机屏高
        driver.swipe(width / 2, height * 7 / 8, width / 2, height * 1 / 8, 200);
    }
    /**向下滑动——swipeDown*/


    /**
     * 获得控件的位置信息
     */
    public static List<Integer> getControlLocation(WebDriver driver, By myBy) {
        Point start = Constant.driverCourier.findElement(myBy).getLocation();
        //获得控件开始位置的坐标轴
        int startX = start.x;
        int startY = start.y;
        System.out.println("startX" + startX);
        System.out.println("startY" + startY);
        //获得控件坐标轴差
        Dimension q = Constant.driverCourier.findElement(myBy).getSize();
        int width = q.getWidth();
        int height = q.getHeight();
        List<Integer> location = new ArrayList<Integer>();
        location.add(startX);
        location.add(startY);
        location.add(width);
        location.add(height);
        return location;
    }

    /**
     * String类型转换成int数组
     * split分隔符
     */
    public static int[] stringToIntArray(String Char, String split) {
        String[] been = Char.split(split);
        int[] abc = new int[been.length];
        for (int i = 0; i < been.length; i++) {
            abc[i] = Integer.parseInt(been[i]);
        }
        return abc;

    }

    public static void runAuto(String[] argv) throws IOException {
        byte exitstatus = run(argv, Thread.currentThread().getContextClassLoader());
        System.out.println("这里面开始往数据库传参数");
        DataStatistics dataStatistics = new DataStatistics();
        dataStatistics.dataStatistics();
        if ((Constant.driverCourier != null)) {
            Constant.driverCourier.quit();
        }
        System.exit(exitstatus);
    }

    public static int runAuto2(String[] argv) throws IOException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList<String>(asList(argv)));

        ResourceLoader resourceLoader = new MultiLoader(classLoader);
        ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
        Runtime runtime = new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
        runtime.run();
        return runtime.exitStatus();

    }

    public static void setAttribute(WebDriver d, WebElement e, String attributeName, String value) {
        JavascriptExecutor js = (JavascriptExecutor) d;
        // 执行JavaScriptdiamante修改页面元素属性。arguments[0]-[2]后面会用e,attributeName,value替换并执行
        js.executeScript("arguments[0].setAttribute(arguments[1],arguments[2])", e, attributeName, value);
    }

    /**
     * 获取本机的mac地址
     */
    public static String getLocalMac() {
        InetAddress ia = null;
        try {
            ia = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        // TODO Auto-generated method stub
        //获取网卡，获取地址
        byte[] mac = new byte[0];
        try {
            mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
        } catch (SocketException e) {
            e.printStackTrace();
        }
//        System.out.println("mac数组长度："+mac.length);
        StringBuffer sb = new StringBuffer("");
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            //字节转换为整数
            int temp = mac[i] & 0xff;
            String str = Integer.toHexString(temp);
//            System.out.println("每8位:"+str);
            if (str.length() == 1) {
                sb.append("0" + str);
            } else {
                sb.append(str);
            }
        }
//        System.out.println("本机MAC地址:"+sb.toString().toUpperCase());
        return sb.toString().toUpperCase();

    }

    /**
     * 根据定位方式，返回该元素是第几个
     * @param driver
     * @param by 例如：
     * @param s
     * @return
     */
    public static int index(WebDriver driver, By by, String s) {
        int temp = 0;
        int i = driver.findElements(by).size();
        for (int n = 0; n < i; n++) {
            if (s.equals(driver.findElements(by).get(n).getText())) {
                temp = n;
            }
        }

        System.out.println("index 是：" + temp);
        return temp;
    }


}
